﻿using EXCEL_LIB;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Util;

namespace BibleBase
{
    public class BibleLoader
    {
        public static void Print(string text)
        {
            List<Verse> verses = new List<Verse>();

            text = text.Replace("&nbsp;", "").Replace("\n", "").Replace("\t", "").Replace(new string(new char[] { (char)160 }), "");
            if (text.Length > 0)
            {
                int verse;
                if (int.TryParse(text, out verse))
                {
                    verses.Add(new Verse { Number = verse, Text = "" });
                }
                else
                {
                    if (text.Length > 1 && !text.Contains("[") && !text.Contains("]"))
                    {
                        string buffer = verses.Last().Text;
                        buffer += (" " + text);
                        while (buffer.Contains("  "))
                            buffer = buffer.Replace("  ", " ");
                        verses.Last().Text = buffer.Trim();
                    }
                }
            }
        }



        static Dictionary<string, List<int>> BOOK_NAMES = new Dictionary<string, List<int>>
        {
            {"Génesis", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}},
            {"Éxodo", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}},
            {"Levítico", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}},
            {"Números", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}},
            {"Deuteronomio", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}},
            {"Josué", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}},
            {"Jueces", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}},
            {"Rut", new List<int> {1, 2, 3, 4}},
            {"1, Samuel", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}},
            {"2, Samuel", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}},
            {"1, Reyes", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}},
            {"2, Reyes", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}},
            {"1, Crónicas", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}},
            {"2, Crónicas", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}},
            {"Esdras", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
            {"Nehemías", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
            {"Ester", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
            {"Job", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42}},
            {"Salmos", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150}},
            {"Proverbios", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}},
            {"Eclesiastés", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}},
            {"Cantares", new List<int> {1, 2, 3, 4, 5, 6, 7, 8}},
            {"Isaías", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66}},
            {"Jeremías", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52}},
            {"Lamentaciones", new List<int> {1, 2, 3, 4, 5}},
            {"Ezequiel", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48}},
            {"Daniel", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}},
            {"Oseas", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}},
            {"Joel", new List<int> {1, 2, 3}},
            {"Amós", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9}},
            {"Abdías", new List<int> {1}},
            {"Jonás", new List<int> {1, 2, 3, 4}},
            {"Miqueas", new List<int> {1, 2, 3, 4, 5, 6, 7}},
            {"Nahúm", new List<int> {1, 2, 3}},
            {"Habacuc", new List<int> {1, 2, 3}},
            {"Sofonías", new List<int> {1, 2, 3}},
            {"Hageo", new List<int> {1, 2}},
            {"Zacarías", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}},
            {"Malaquías", new List<int> {1, 2, 3, 4}},
            {"Mateo", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}},
            {"Marcos", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
            {"Lucas", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}},
            {"Juan", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}},
            {"Hechos", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}},
            {"Romanos", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
            {"1, Corintios", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
            {"2, Corintios", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
            {"Gálatas", new List<int> {1, 2, 3, 4, 5, 6}},
            {"Efesios", new List<int> {1, 2, 3, 4, 5, 6}},
            {"Filipenses", new List<int> {1, 2, 3, 4}},
            {"Colosenses", new List<int> {1, 2, 3, 4}},
            {"1, Tesalonicenses", new List<int> {1, 2, 3, 4, 5}},
            {"2, Tesalonicenses", new List<int> {1, 2, 3}},
            {"1, Timoteo", new List<int> {1, 2, 3, 4, 5, 6}},
            {"2, Timoteo", new List<int> {1, 2, 3, 4}},
            {"Tito", new List<int> {1, 2, 3}},
            {"Filemón", new List<int> {1}},
            {"Hebreos", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
            {"Santiago", new List<int> {1, 2, 3, 4, 5}},
            {"1, Pedro", new List<int> {1, 2, 3, 4, 5}},
            {"2, Pedro", new List<int> {1, 2, 3}},
            {"1, Juan", new List<int> {1, 2, 3, 4, 5}},
            {"2, Juan", new List<int> {1}},
            {"3, Juan", new List<int> {1}},
            {"Judas", new List<int> {1}},
            {"Apocalipsis", new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}},
        };

        public static Bible LoadBible(string version, string savePath)
        {
            Bible bible;
            if (File.Exists(savePath))
                bible = PersistentObject.DeSerialize<Bible>(savePath);
            else
                bible = new Bible { Name = version };
            Parallel.ForEach(BOOK_NAMES, (pair) =>
                {
                    string name = pair.Key;
                    List<int> verses = pair.Value;

                    BibleLoader.LoadBook(version, bible, name, verses, savePath);
                    Logger.WriteLine("Book {0} completed", name);
                });
            return bible;
        }

        public static string LoadFromBibleGateway(string version, string book, int chapter)
        {
            try
            {
                var client = new WebClient();
                string url = @"http://www.biblegateway.com/passage/?search=" + book + @"+" + chapter + @"&version=" + version;
                Stream stream = client.OpenRead(url);
                StreamReader reader = new StreamReader(stream);
                return reader.ReadToEnd();
            }
            catch
            {
                Thread.Sleep(5000);
                return LoadFromBibleGateway(version, book, chapter);
            }
        }

        public static void LoadChapter(string version, Bible bible, string bookName, int chapterNum, string savePath)
        {
            Book book = bible.Books.FirstOrDefault(x => x.Name == bookName);
            Chapter chapter = book.Chapters.FirstOrDefault(x => x.Number == chapterNum);
            if (chapter == null)
            {
                Logger.WriteLine("Loading chapter: {0}, {1}", bookName, chapterNum);

                chapter = new Chapter { Number = chapterNum };
                book.Chapters.Add(chapter);

                string t = LoadFromBibleGateway(version, bookName, chapterNum);

                t = t.Replace("\n", "").Replace("\t", "");
                var parts = t.Split(new char[] { '<' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                bool started = false;
                bool ignoreTitle = false;
                int spans = 0;
                int spansOnStarted = 0;
                foreach (var text in parts)
                {
                    var sparts = text.Split(new char[] { '>' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                    if (sparts.Count > 2)
                    { }
                    else
                    {
                        if (sparts.Count > 0)
                        {
                            if (started && sparts.Count > 1)
                            {
                                string content = sparts[1].Replace("&nbsp;", "").Trim();
                                if (content.Length > 1)
                                {
                                    if (content.Contains("Footnotes"))
                                    {
                                        if (!content.StartsWith("Footnotes"))
                                            Debugger.Break();
                                        break;
                                    }
                                    if (content.Contains("Nueva Versión"))
                                    {
                                        if (!content.StartsWith("Nueva Versión"))
                                            Debugger.Break();
                                        break;
                                    }
                                    if (content.Contains("Reina-Valera"))
                                    {
                                        if (!content.StartsWith("Reina-Valera"))
                                            Debugger.Break();
                                        break;
                                    }
                                    if (content.Contains("Cross references"))
                                    {
                                        if (!content.StartsWith("Cross references"))
                                            Debugger.Break();
                                        break;
                                    }
                                    if (content.Contains(")'"))
                                    {
                                        if (content.Length > 2)
                                            Debugger.Break();
                                    }
                                    int num;
                                    if (!int.TryParse(content, out num) && !ignoreTitle)
                                    {
                                        if (content != ")'")
                                        {
                                            string txt = chapter.Verses.Last().Text + " " + content;
                                            while (txt.Contains("  "))
                                                txt = txt.Replace("  ", " ");
                                            chapter.Verses.Last().Text = txt.Trim();
                                        }
                                    }
                                }
                            }

                            if (text.StartsWith("h3"))
                            {
                                ignoreTitle = true;
                            }
                            else if (text.StartsWith("/h3"))
                            {
                                ignoreTitle = false;
                            }

                            if (text.StartsWith("span"))
                            {
                                string tagData = sparts[0];
                                var ssparts = tagData.Split(new char[] { '=', ' ', '"' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                                if (ssparts.Count > 3)
                                {
                                    if (ssparts.Contains("span") && ssparts.Contains("text"))
                                    {
                                        started = true;
                                        spansOnStarted = spans;
                                        string id = ssparts[ssparts.IndexOf("text") + 1];
                                        var iparts = id.Split(new char[] { '-' }).ToList();
                                        int vers = int.Parse(iparts.Last());
                                        if (chapter.Verses.Count == 0 || chapter.Verses.Last().Number < vers)
                                            chapter.Verses.Add(new Verse { Number = vers });
                                    }
                                }

                            }
                        }
                    }
                }

                lock (bible)
                    PersistentObject.Serialize<Bible>(savePath, bible);
            }
            else
                Logger.WriteLine("Skipping chapter: {0}, {1}", bookName, chapterNum);
        }
#if _
        public static Chapter LoadChapter2(string content)
        {
            List<Verse> verses = new List<Verse>();

            string sep1 = "<sup class=\"versenum\">";
            string sep2 = "<span class=\"chapternum\">";
            var parts = content.Split(new string[] { sep1, sep2 }, StringSplitOptions.None).ToList();

            if (parts.Count > 1)
            {
                parts.RemoveAt(0);
                parts.RemoveAt(parts.Count - 1);
                parts.ForEach(x =>
                    {
                        string[] xparts = x.Split(new char[] { '<' });
                        xparts.ToList().ForEach(y =>
                            {
                                string[] yparts = y.Split(new char[] { '>' });
                                if (yparts.Count() > 2)
                                {
                                    Logger.WriteLine("Descartando:");
                                    yparts.ToList().ForEach(d => Logger.WriteLine(d));
                                }
                                if (yparts.Count() == 1)
                                    Print(yparts[0]);
                                else
                                    Print(yparts[1]);
                            });
                    });

                return new Chapter { Verses = verses };
            }

            return null;
        }

        public static Chapter LoadChapter1(string book, int chapter)
        {
            List<Verse> verses = new List<Verse>();

            string content = LoadFromBibleGateway(book, chapter);

            string sep1 = "<sup class=\"versenum\">";
            string sep2 = "<span class=\"chapternum\">";
            var parts = content.Split(new string[] { sep1, sep2 }, StringSplitOptions.None).ToList();

            if (parts.Count > 1)
            {
                parts.RemoveAt(0);
                parts.RemoveAt(parts.Count - 1);
                parts.ForEach(x =>
                {
                    string[] xparts = x.Split(new char[] { '<' });
                    xparts.ToList().ForEach(y =>
                    {
                        string[] yparts = y.Split(new char[] { '>' });
                        if (yparts.Count() > 2)
                        {
                            Logger.WriteLine("Descartando:");
                            yparts.ToList().ForEach(d => Logger.WriteLine(d));
                        }
                        if (yparts.Count() == 1)
                            Print(yparts[0]);
                        else
                            Print(yparts[1]);
                    });
                });

                return new Chapter { Verses = verses };
            }

            return null;
        }

        //public static Book LoadBook(string name)
        //{
        //    Logger.WriteLine("Loading: {0}", name);

        //    Book book = new Book(name);

        //    int chapterNum = 1;
        //    Chapter chapter = LoadChapter(book, name, chapterNum, null);

        //    while (chapter != null)
        //    {
        //        Logger.WriteLine("Chapter: {0}", chapterNum);
        //        book.Chapters.Add(chapter);
        //        chapterNum++;
        //        chapter = LoadChapter(chapterNum, LoadFromBibleGateway(name, chapterNum));
        //    }

        //    return book;
        //}
#endif
        public static void LoadBook(string version, Bible bible, string bookName, List<int> chapters, string savePath)
        {
            Book book = bible.Books.FirstOrDefault(x => x.Name == bookName);
            if (book == null)
            {
                Logger.WriteLine("Loading book: {0}", bookName);
                book = new Book { Name = bookName };
                bible.Books.Add(book);
            }
            else
                Logger.WriteLine("Skipping book: {0}", bookName);

            Parallel.ForEach(chapters, (chapterNum) =>
                {
                    LoadChapter(version, bible, bookName, chapterNum, savePath);
                });
        }

        public static void SortBible(Bible nvi)
        {
            List<Book> ordered = new List<Book>();
            foreach (string name in BOOK_NAMES.Keys)
            {
                Book book = nvi.Books.FirstOrDefault(x => x.Name == name);
                if (book != null)
                {
                    ordered.Add(book);
                    book.Sort();
                }
            }
            nvi.Books = ordered;
        }

        public static Abreviaturas LoadAbreviaturas(string path)
        {
            Abreviaturas abreviaturas = new Abreviaturas();
            ExcelSession excel = new ExcelSession();
            var ws = excel.Open(path);
            Logger.WriteLine("Total abreviaturas: {0}", ws.Rows.Count);
            int errors = 0;
            for (int i = 1; i < ws.Rows.Count; i++)
            {
                if (!abreviaturas.Add(ws.Cells[i, 1].Text, ws.Cells[i, 2].Text, ws.Cells[i, 3].Text))
                {
                    Logger.WriteLine("Item ignorado: {0}, {1}, {2}",
                                ws.Cells[i, 1].Text, ws.Cells[i, 2].Text, ws.Cells[i, 3].Text);
                    break;
                }
                Logger.WriteLine("Actual abreviaturas: {0}", i);
            }
            excel.Close();
            excel.Quit();

            return abreviaturas;
        }
    }
}
